package com.zcj.demo.user.service;

import com.zcj.demo.config.EasyTypeToken;
import com.zcj.demo.mq.RabbitMqSender;
import com.zcj.demo.user.domain.UserDO;
import com.zcj.demo.user.repository.UserRepository;
import com.zcj.demo.user.service.dto.UserDTO;
import com.zcj.demo.user.service.mapper.UserMapper;
import com.zcj.demo.utils.RedisUtils;
import com.zcj.demo.web.errors.AuthException;
import com.zcj.demo.web.errors.BusinessException;
import com.zcj.demo.web.user.vo.LoginVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.mindrot.jbcrypt.BCrypt;
import org.springframework.stereotype.Service;

/**
 * @author 68300119
 * @Date 2020/10/13
 **/
@Service
@Slf4j
public class AccountService {

    private final UserRepository userRepository;

    private final RedisUtils redisUtils;

    private final RabbitMqSender rabbitMqSender;

    private final UserMapper userMapper;

    private final UserService userService;


    public AccountService(UserRepository userRepository,
                          RedisUtils redisUtils,
                          RabbitMqSender rabbitMqSender,
                          UserMapper userMapper,
                          UserService userService) {
        this.userRepository = userRepository;
        this.redisUtils = redisUtils;
        this.rabbitMqSender = rabbitMqSender;
        this.userMapper = userMapper;
        this.userService = userService;
    }


    /**
     * 获取验证码
     *
     * @param mobile 手机号
     * @return
     */
    public void sendCaptcha(String mobile) {
        // 随机六位数字
        String code = String.valueOf((int) ((Math.random() * 9 + 1) * 100000));
        // 发送短信
        rabbitMqSender.sendSms(mobile, code);
        String securityCode = BCrypt.hashpw(code, BCrypt.gensalt());
        redisUtils.set("captcha:" + mobile, securityCode, 600);
    }

    /**
     * 登录
     *
     * @param params 登录参数
     */
    public void login(LoginVO params) {
        if ("account".equals(params.getType())) {
            this.loginByPassword(params);
        }
        if ("mobile".equals(params.getType())) {
            this.loginByMobile(params);
        }
    }

    /**
     * 通过账号密码登录
     *
     * @param params 登录信息
     * @return token
     */
    private void loginByPassword(LoginVO params) {
        // 获取当前用户
        Subject subject = SecurityUtils.getSubject();
        // 封装用户登录数据
        EasyTypeToken token = new EasyTypeToken(params.getUsername(), params.getPassword());
        token.setRememberMe(true);
        // 执行登录方法，如果没有异常就成功
        try {
            subject.login(token);
        } catch (UnknownAccountException uae) {
            throw new AuthException("用户名错误！");
        } catch (IncorrectCredentialsException ice) {
            // 密码错误
            log.info("Password for account " + token.getPrincipal() + " was incorrect!");
            throw new AuthException("密码错误！");
        } catch (LockedAccountException lae) {
            // 用户锁定
            log.info("The account for username " + token.getPrincipal() + " is locked.  " +
                    "Please contact your administrator to unlock it.");
            throw new AuthException("用户锁定,请联系管理员解锁！");
        }
    }

    /**
     * 通过手机登录
     *
     * @param params 登录信息
     * @return token
     */
    private void loginByMobile(LoginVO params) {
        UserDO account = userRepository.findByPhone(params.getMobile()).orElseThrow(AuthException::new);
        try {
            String code = (String) redisUtils.get("captcha:" + params.getMobile());
            if (BCrypt.checkpw(params.getCaptcha(), code)) {
                // 获取当前用户
                Subject subject = SecurityUtils.getSubject();
                // 封装用户登录数据
                UsernamePasswordToken token = new EasyTypeToken(account.getUsername());
                subject.login(token);
                redisUtils.del("captcha:" + params.getMobile());
                return;
            }
            throw new AuthException("手机号或者验证码不正确");
        } catch (Exception e) {
            throw new AuthException("手机号或者验证码不正确");
        }
    }

    /**
     * 注册
     *
     * @param user 用户信息
     * @return 用户信息
     */
    public UserDTO register(UserDTO user) {
        if (!user.getPassword().equals(user.getConfirm())) {
            throw new BusinessException("两次密码输入不一致");
        }
        String captcha = (String) redisUtils.get("captcha:" + user.getPhone());

        if (!BCrypt.checkpw(user.getCaptcha(), captcha)) {
            throw new BusinessException("手机验证码错误");
        }
        UserDTO userDTO = userService.create(user);
        redisUtils.del("captcha:" + user.getPhone());
        return userDTO;
    }
}
